package com.yanqu.road.server.manager.activity.sonhai;

import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.entity.FieldTypeAnnotation;
import com.yanqu.road.entity.activity.sonhai.config.*;
import com.yanqu.road.entity.activity.sonhai.data.*;
import com.yanqu.road.entity.activity.sonhai.enums.*;
import com.yanqu.road.entity.activity.sonhai.param.*;
import com.yanqu.road.entity.activity.suitang.data.CrossSuiTangUserData;
import com.yanqu.road.entity.activity.suitang.entity.union.CrossSuiTangUnionJoinMember;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.eChatContentType;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eOccupationType;
import com.yanqu.road.entity.log.cross.sonhai.LogCrossSonHaiBattle;
import com.yanqu.road.entity.log.cross.sonhai.LogCrossSonHaiEnergy;
import com.yanqu.road.entity.log.cross.sonhai.LogCrossSonHaiUserDie;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.rank.cross.CrossUserRank;
import com.yanqu.road.entity.rank.yrank.UserYRank;
import com.yanqu.road.entity.union.activitygroup.UnionActivityGroupUnion;
import com.yanqu.road.entity.union.activitygroup.UnionActivityGroupUser;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.logic.cross.CrossActivityRankListModel;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.activity.CommonTeamProto;
import com.yanqu.road.pb.activity.SonHaiProto;
import com.yanqu.road.pb.rank.RankProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.activity.ActivityRankMgr;
import com.yanqu.road.server.manager.activity.commonteam.CommonTeamMgr;
import com.yanqu.road.server.manager.activity.sonhai.pb.SonHaiActivityPb;
import com.yanqu.road.server.manager.config.GoodsMgr;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.union.activitygroup.Cross2UnionActivityGroupMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manager.yrank.CrossYRankCacheMgr;
import com.yanqu.road.server.manager.yrank.CrossYRankMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.FixSizeLinkedList;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.energy.EnergyRestoreResult;
import com.yanqu.road.utils.energy.EnergyUtils;
import com.yanqu.road.utils.plot.PlotUtil;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class CrossSonHaiUser extends SonHaiUserData {

    /**
     * logger
     */
    private static Logger logger = LogManager.getLogger(CrossSonHaiUser.class.getName());

    /**
     * 活动配置
     */
    private SonHaiConfig sonHaiConfig;

    /**
     * 区域数据
     */
    private SonHaiRegionData regionData;

    /**
     * 攻击我的玩家地块MAP,K:userId
     */
    private Map<Long, SonHaiPlotData> attackMeUserPlotMap = new ConcurrentHashMap<>();

    /**
     * 兽蛋孵化奖励MAP
     */
    private Map<Integer, SonHaiUserEggRewardData> userEggRewardDataMap = new ConcurrentHashMap<>();

    /**
     * 玩家持有兽蛋MAP
     */
    private Map<Integer, SonHaiEggData> userEggDataMap = new ConcurrentHashMap<>();

    /**
     * 蛋蛋被抢信息MAP
     */
    private Map<Integer, SonHaiLostEggData> lostEggMap = new ConcurrentHashMap<>();

    /**
     * 战斗争夺日志
     */
    private FixSizeLinkedList<SonHaiBattleLog> battleLogList = new FixSizeLinkedList<>(20);

    /**
     * 构造
     * @param sonHaiConfig
     * @param groupId
     * @param userId
     * @param teamId
     * @param serverId
     * @param energy
     */
    public CrossSonHaiUser(SonHaiConfig sonHaiConfig, int groupId, long userId, int teamId, long serverId, int energy, int nextBuffComeNeedEnergy, long power, int helpNum, String language) {
        super(sonHaiConfig.getActivityInfo().getActivityId(), groupId, userId, teamId, serverId, energy, nextBuffComeNeedEnergy, sonHaiConfig.getPvpAttackedNumInit(), power, helpNum, language);
        this.sonHaiConfig = sonHaiConfig;
    }

    public CrossSonHaiUser(SonHaiConfig sonHaiConfig, SonHaiUserData userData, SonHaiRegionData regionData, Map<Long, SonHaiPlotData> attackMeUserPlotMap, Map<Integer, SonHaiUserEggRewardData> userEggRewardDataMap, Map<Integer, SonHaiEggData> occupyEggMap) {
        super(userData);
        this.sonHaiConfig = sonHaiConfig;
        this.regionData = regionData;
        this.attackMeUserPlotMap = attackMeUserPlotMap;
        this.userEggRewardDataMap = userEggRewardDataMap;
        this.userEggDataMap = occupyEggMap;
    }

    public void refreshConfig(SonHaiConfig sonHaiConfig) {
        this.sonHaiConfig = sonHaiConfig;
    }

    public SonHaiConfig getConfig() {
        return sonHaiConfig;
    }

    public Map<Long, SonHaiPlotData> getAttackMeUserPlotMap() {
        return attackMeUserPlotMap;
    }

    public void addAttackMeUserPlot(SonHaiPlotData plotData) {
        this.attackMeUserPlotMap.put(plotData.getUserId(), plotData);
    }

    public void removeAttackMeUserPlot(long userId) {
        this.attackMeUserPlotMap.remove(userId);
    }

    /**
     * 获取队伍
     * @return
     */
    public CrossSonHaiTeam getTeam() {
        CrossSonHaiActivity activity = CrossSonHaiActivityMgr.getActivity(this.getActivityId(), this.getGroupId());
        return activity.getTeam(this.getTeamId());
    }

    /**
     * 添加蛋奖励
     * @param eggData
     */
    public void addUserEggRewardData(SonHaiEggData eggData, SonHaiActivityData activityData) {
        //玩家移除战令兽蛋
        this.removeOccupyEgg(eggData.getId());
        //相同蛋ID,同一天不重复添加
        for (SonHaiUserEggRewardData item : this.userEggRewardDataMap.values()) {
            boolean sameDay = DateHelper.checkTimeOneDay(System.currentTimeMillis(), item.getCreateTime());
            if (sameDay && item.getEggId() == eggData.getId()) {
                return;
            }
        }
        //读取配置，获取蛋奖励
        SonHaiEggConfig eggConfig = this.sonHaiConfig.getEggConfig(eggData.getEggConfigId());
        Property rewardProperty = PropertyHelper.parseNewStringToProperty(eggConfig.getReward());
        if (rewardProperty.isNothing()) {
            logger.error("山海伏兽-添加蛋奖励-奖励为空：{}, {}, {}", eggData.getId(), eggConfig, rewardProperty);
            return;
        }
        String reward = PropertyHelper.parsePropertyToString(rewardProperty);
        SonHaiUserEggRewardData userEggRewardData = new SonHaiUserEggRewardData(
                activityData.getMaxEggRewardIdAndAdd(),
                this.sonHaiConfig.getActivityInfo().getActivityId(),
                this.getGroupId(),
                this.getUserId(),
                eggData.getId(),
                reward
        );
        this.userEggRewardDataMap.put(userEggRewardData.getId(), userEggRewardData);
    }

    /**
     * 持有兽蛋MAP
     * @return
     */
    public Map<Integer, SonHaiEggData> getUserEggDataMap() {
        return userEggDataMap;
    }

    /**
     * 获取未领取的兽蛋奖励
     * @return
     */
    public int getNotReceiveEggRewardNum() {
        int num = 0;
        for (SonHaiUserEggRewardData item : this.userEggRewardDataMap.values()) {
            if (item.getRewardFlag() == SonHaiRewardFlagEnum.GET_NOT.getType()) {
                num++;
            }
        }
        return num;
    }

    /**
     * 获取兽蛋奖励MAP
     * @return
     */
    public Map<Integer, SonHaiUserEggRewardData> getUserEggRewardDataMap() {
        return userEggRewardDataMap;
    }

    /**
     * 获取兽蛋奖励
     * @param id
     * @return
     */
    public SonHaiUserEggRewardData getUserEggRewardData(int id) {
        return this.userEggRewardDataMap.get(id);
    }

    /**
     * 注入区域
     * @param regionData
     */
    public void setRegion(SonHaiRegionData regionData) {
        this.setRegionId(regionData.getRegionId());
        this.regionData = regionData;
    }

    /**
     * 注入位置
     * @param x
     * @param y
     */
    public void setPosition(int x, int y) {
        this.setX(x);
        this.setY(y);
        //同步同一个区域里的队伍，我的位置变更了
        SonHaiProto.SonHaiSyncUserPositionChangeMsg.Builder  builder = SonHaiProto.SonHaiSyncUserPositionChangeMsg.newBuilder();
        builder.setActivityId(this.getActivityId());
        builder.setUserId(this.getUserId());
        builder.setX(x);
        builder.setY(y);
        for (CrossSonHaiUser member : this.getTeam().getMemberMap().values()) {
            if (member.getRegionId() == this.getRegionId() && member.getUserId() != this.getUserId()) {
                MessageHelper.sendPacket(member.getServerId(), member.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_SYNC_USER_POSITION_CHANGE, builder));
            }
        }
    }

    /**
     * 注入区域，位置
     * @param regionData
     * @param x
     * @param y
     */
    public void setRegionAndPosition(SonHaiRegionData regionData, int x, int y) {
        this.setRegion(regionData);
        this.setPosition(x, y);
    }

    /**
     * 获取玩家区域数据
     * @return
     */
    public SonHaiRegionData getRegionData() {
        return this.regionData;
    }

    /**
     * 获取寻踪进度
     * @return
     */
    public int getProgress() {
        return this.getRegionData().getProgress();
    }

    /**
     * 判断是否被玩家打过
     * @param userId
     * @return
     */
    public boolean checkUserBeAttack(long userId) {
        return this.getReBloodInfoMap().containsKey(userId);
    }

    /**
     * 蛋蛋丢失信息MAP
     * @return
     */
    public Map<Integer, SonHaiLostEggData> getLostEggMap() {
        return lostEggMap;
    }

    /**
     * 推送蛋蛋丢失
     * @param eggData
     * @param targetUserId
     */
    public void addLostEggMsg(SonHaiEggData eggData, long targetUserId) {
        SonHaiLostEggData lostEggData = new SonHaiLostEggData(eggData, targetUserId);
        this.lostEggMap.put(eggData.getId(), lostEggData);
        //推送蛋蛋丢失
        this.pushLostEggMsg();
    }

    /**
     * 推送占领的蛋被抢
     */
    public void pushLostEggMsg() {
        if (!this.lostEggMap.isEmpty()) {
            SonHaiProto.SonHaiPushOccupyEggBeTakenMsg.Builder builder = SonHaiProto.SonHaiPushOccupyEggBeTakenMsg.newBuilder();
            for (SonHaiLostEggData lostEggData : this.lostEggMap.values()) {
                //推送蛋蛋丢失
                SonHaiProto.SonHaiPushOccupyEggBeTakenMsgItem.Builder item  = SonHaiProto.SonHaiPushOccupyEggBeTakenMsgItem.newBuilder();
                CrossUserBaseInfo targetUserBaseInfo = CrossUserMgr.getCrossUserBaseInfo(lostEggData.getTargetUserId());
                if (targetUserBaseInfo != null && targetUserBaseInfo.getUserBaseInfo() != null) {
                    item.setUserInfo(PlayerBasePb.parsePlayerBaseTempMsg(targetUserBaseInfo.getUserBaseInfo()));
                }
                item.setEggData(SonHaiActivityPb.buildSonHaiEggData(lostEggData.getEggData(), this.getLanguage()));
                builder.addItem(item);
            }
            MessageHelper.sendPacket(this.getServerId(), this.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_PUSH_OCCUPY_EGG_BE_TAKEN_MSG, builder));
        }
    }

    /**
     * 移除蛋被抢信息
     * @param eggId
     */
    public void removeLostEgg(int eggId) {
        this.lostEggMap.remove(eggId);
    }

    /**
     * 获取增加的积分
     * @param allScore 总积分
     * @param allBlood 总血量
     * @param realDamage 真实伤害
     * @return
     */
    private long getAddScore(long allScore, long allBlood, long realDamage) {
        BigDecimal rate = BigDecimal.valueOf(realDamage).divide(BigDecimal.valueOf(allBlood), 8, RoundingMode.DOWN);
        //向上取整
        return BigDecimal.valueOf(allScore).multiply(rate).setScale(0, RoundingMode.UP).longValue();
    }

    /**
     * 添加积分-根据真实伤害
     * @param allScore 总积分
     * @param allBlood 总血量
     * @param realDamage 真实伤害
     * @param rate 积分buff加减益比例
     * @param value 积分buff加减益值
     * @return
     */
    public long addScoreByRealDamage(long allScore, long allBlood, long realDamage, int rate, long value) {
        long addScore = this.getAddScore(allScore, allBlood, realDamage);
        //计算额外增减的积分extraAddScore可能是负数
        BigDecimal rateBig = BigDecimal.valueOf(rate).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
        long extraAddScore = BigDecimal.valueOf(addScore).multiply(rateBig).setScale(0, RoundingMode.UP).longValue();
        //最终增加的积分
        long finalAddScore = Math.max(addScore + extraAddScore + value, 0);
        //增加
        this.addScore(finalAddScore);
        return finalAddScore;
    }

    /**
     * 添加积分-剩余全部积分
     * @param regionData 区域信息
     * @param plotData 地块信息
     * @return
     */
    public long addScoreByPlot(SonHaiRegionData regionData, SonHaiPlotData plotData, int progress) {
        long resideBlood = 1;
        long allBlood = 1;
        if (plotData.getBeastData() != null) {
            resideBlood = plotData.getBeastData().getBlood();//剩余的血
            allBlood = plotData.getBeastData().getAllBlood();//总血量
        }
        long allScore = this.sonHaiConfig.getEventAllScore(plotData.getRegionId(), plotData.getPlotId());//总积分
        //积分加成rate
        int rate = this.getScoreOpRate(regionData, plotData.getX(), plotData.getY(), true, plotData.getLevel(), progress);
        //积分加成value
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(plotData.getPlotId());
        long value = this.getScoreOpValue(true, eventConfig.getSchedule());
        return this.addScoreByRealDamage(allScore, allBlood, resideBlood, rate, value);
    }

    /**
     * 增加积分
     * @param addScore
     */
    public void addScore(long addScore) {
        this.setScore(this.getScore() + addScore);
        //个人榜单变更
        this.changeUserRank();
//        //通知区服,更新成就condition  2024-06-24 成就需求删除
//        SonHaiProto.SonHaiScoreChangeFromCrossMsg.Builder msg = SonHaiProto.SonHaiScoreChangeFromCrossMsg.newBuilder();
//        msg.setActivityId(this.sonHaiConfig.getActivityInfo().getActivityId());
//        msg.setScore(this.getScore());
//        MessageHelper.sendPacket(this.getServerId(), this.getUserId(), YanQuMessageUtils.buildMessage(Protocol.S_SON_HAI_SCORE_CHANGE_FROM_CROSS, msg));
    }

    /**
     * 添加山海灵气
     * @param addAuraScore
     */
    public synchronized void addAuraScore(long addAuraScore) {
        long newAuraScore = this.getAuraScore() + addAuraScore;
        if (newAuraScore < 0) {
            newAuraScore = 0;
        }
        this.setAuraScore(newAuraScore);
    }

    /**
     * 个人积分榜变更
     */
    public void changeUserRank(){
        UserYRank userYRank = new UserYRank();
        userYRank.setUserId(this.getUserId());
        userYRank.setActivityId(this.getActivityId());
        userYRank.setGroupId(this.getGroupId());
        userYRank.setIdKey(String.valueOf(eGamePlayerEventType.SonHaiUserRank.getValue()));
        userYRank.setValue(BigInteger.valueOf(this.getScore()));
        userYRank.setUpdateTime(System.currentTimeMillis());
        userYRank.setUserBaseInfo(CrossUserMgr.getUserBaseInfo(this.getUserId()));
        CrossYRankMgr.userRankChange(userYRank);
    }

    /**
     * 玩家积分榜单排名
     */
    public int getUserRank(){
        long userId = this.getUserId();
        int rank = -1;
        CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId);
        if (userBaseInfo != null) {
            String rankType = String.valueOf(eGamePlayerEventType.SonHaiUserRank.getValue());
//            List<UserYRank> rankList = CrossYRankMgr.getSortUserRankList(this.getActivityId(), this.getGroupId(), rankType);
//            rank = CrossYRankMgr.getUserRankNum(rankList, this.getUserId());
            RankProto.RankListMsg.Builder rankBuilder = CrossYRankCacheMgr.getUserRankList(this.getActivityId(), this.getGroupId(), rankType);
            rank = CrossYRankCacheMgr.getUserRank(this.getActivityId(), this.getGroupId(), rankType, rankBuilder, this.getUserId());
        }
        return rank;
    }

    /**
     * 获取玩家排名前后num排名的玩家列表
     * @return
     */
    public List<UserYRank> getUserSubRankList(int start, int end) {
        //我的排行
        int myRank = this.getUserRank();
        if (myRank == -1) {
            return null;
        }
        String rankType = String.valueOf(eGamePlayerEventType.SonHaiUserRank.getValue());
        List<UserYRank> rankList = CrossYRankMgr.getSortUserRankList(this.getActivityId(), this.getGroupId(), rankType);
        return CrossYRankMgr.getSubListWithoutIndex(rankList, myRank, start, end);
    }

    /**
     * 获取当前血量
     * @return
     */
    public long getBlood() {
       return this.getAllBlood() - this.getReBlood();
    }

    /**
     * 获取血量比率
     * @return
     */
    public int getBloodRate() {
        long blood = this.getBlood();
        long allBlood = this.getAllBlood();
        if (allBlood == 0) {
            return 0;
        }
        return BigDecimal.valueOf(blood).divide(BigDecimal.valueOf(allBlood), 8, RoundingMode.DOWN).multiply(BigDecimal.valueOf(100)).intValue();
    }

    /**
     * 添加体力-不能超上限
     * @param energy
     */
    public synchronized int addEnergyNotFull(int energy) {
        //恢复一下
        this.energyRestore();
        //最大体力
        int maxEnergy = this.sonHaiConfig.getEnergyLimit();
        if (this.getEnergy() >= maxEnergy) {
            return 0;
        }
        //加上后的体力
        int newEnergy = this.getEnergy() + energy;
        if (newEnergy > maxEnergy) {
            newEnergy = maxEnergy;
        }
        int recoverEnergy = newEnergy - this.getEnergy();//恢复了多少体力
        this.setEnergy(newEnergy);
        return recoverEnergy;
    }

    /**
     * 添加体力-能超上限
     * @param energy
     */
    public synchronized void addEnergy(int energy) {
        //恢复一下
        this.energyRestore();
        this.setEnergy(this.getEnergy() + energy);
    }

    /**
     *  减少体力
     * @param reEnergy
     * @return
     */
    public synchronized boolean reduceEnergy(int reEnergy) {
        //恢复体力
        this.energyRestore();
        //检查体力是否充足
        boolean enoughFlag = this.checkEnergyEnough(reEnergy);
        if (enoughFlag) {
            //减少体力
            int newEnergy = this.getEnergy() - reEnergy;
            this.setEnergy(newEnergy);
            //增加【消耗体力，增加协助次】计数
            this.addUseEnergyAddHelpNumCount(reEnergy);
            //check圣兽降临
            this.buffCome(reEnergy);
            //体力消耗日志
            LogCrossSonHaiEnergy log = new LogCrossSonHaiEnergy(
                    this.getActivityId(),
                    this.getGroupId(),
                    this.getUserId(),
                    this.getTeamId(),
                    SonHaiLogEnergyTypeEnum.COST.getType(),
                    reEnergy,
                    this.getEnergy()
            );
            CrossAutoLogMgr.add(log);
        }
        return enoughFlag;
    }

    /**
     * 减少体力：探索
     *
     * @return 体力是否足够，true：足够，false：不足
     */
    public boolean exploreReduceEnergy() {
        //读取配置，体力消耗值
        SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(this.regionData.getRegionId());
        int reEnergy = floorConfig.getEnergy();
        return this.reduceEnergy(reEnergy);
    }

    /**
     * 检查体力是否足够-探索
     * @return
     */
    public boolean checkExploreEnergyEnough() {
        //恢复体力
        this.energyRestore();
        //读取配置，体力消耗值
        SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(this.regionData.getRegionId());
        int reEnergy = floorConfig.getEnergy();
        return this.checkEnergyEnough(reEnergy);
    }

    /**
     * 检查体力是否足够
     * @param reEnergy
     * @return
     */
    public boolean checkEnergyEnough(int reEnergy) {
        //判断玩家体力是否足够
        if (this.getEnergy() >= reEnergy) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 恢复体力：冷却
     */
    public void energyRestore() {
        //上次恢复体力时间
        long lastRestoreTime = this.getEnergyRestoreTime();
        //体力CD时间（s）
        int restoreDuration = this.sonHaiConfig.getEnergyCd();
        //恢复数量
        int restoreNum = this.sonHaiConfig.getEnergyCdNum();
        //当前体力
        long energy = this.getEnergy();
        //最大体力
        int maxEnergy = this.sonHaiConfig.getEnergyLimit();
        //恢复体力
        EnergyRestoreResult energyRestoreResult = EnergyUtils.energyRestore(lastRestoreTime, System.currentTimeMillis(), restoreDuration, restoreNum, maxEnergy, energy);
        long recoverEnergy = energyRestoreResult.getEnergyAfterRestore() - energy;
        //增加体力
        this.setEnergy((int) energyRestoreResult.getEnergyAfterRestore());
        this.setEnergyRestoreTime(energyRestoreResult.getRestoreTime());
        //体力恢复日志
        if (recoverEnergy > 0) {
            LogCrossSonHaiEnergy log = new LogCrossSonHaiEnergy(
                    this.getActivityId(),
                    this.getGroupId(),
                    this.getUserId(),
                    this.getTeamId(),
                    SonHaiLogEnergyTypeEnum.SYSTEM_ADD.getType(),
                    (int) recoverEnergy,
                    this.getEnergy()
            );
            CrossAutoLogMgr.add(log);
        }
    }

    /**
     * 获取使用掉的体力
     * @return
     */
    public int getUseEnergy() {
        //当前体力
        int energy = this.getEnergy();
        //最大体力
        int maxEnergy = this.sonHaiConfig.getEnergyLimit();
        if (energy >= maxEnergy) {
            return 0;
        } else {
            return maxEnergy - energy;
        }
    }

    /**
     * 使用道具恢复体力
     * @param propId
     * @param num
     * @return int 实际需要扣除的道具数量
     * @throws BusinessException
     */
    public void usePropRecoverEnergy(int propId, int num) throws BusinessException {
        GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(propId);
        if (goodsInfo == null) {
            throw new BusinessException(GameErrorCode.E_GOODS_NO_EXIST);
        }
        //获取增加的体力值
        int oneAddEnergy = goodsInfo.getParamList().get(0).intValue();
        int addEnergy = oneAddEnergy * num;
        this.addEnergy(addEnergy);
        //体力恢复日志
        LogCrossSonHaiEnergy log = new LogCrossSonHaiEnergy(
                this.getActivityId(),
                this.getGroupId(),
                this.getUserId(),
                this.getTeamId(),
                SonHaiLogEnergyTypeEnum.PROP_ADD.getType(),
                addEnergy,
                this.getEnergy()
        );
        CrossAutoLogMgr.add(log);
    }

//    /**
//     * 增加【每消耗N1体力恢复N2协助次数】计数
//     *
//     * @param energyNum
//     */
//    public void addUseEnergyAddHelpNumCount(int energyNum) {
//        //读取配置【每消耗N1体力恢复N2协助次数】
//        int useEnergyNum = this.sonHaiConfig.getCostEnergyHelpNum().get(0);//读配置 N1
//        int addHelpNum = this.sonHaiConfig.getCostEnergyHelpNum().get(1);//都配置 N2
//        //新计数
//        int newUseEnergyAddHelpNumCount = this.getUseEnergyAddHelpNumCount() + energyNum;
//        //判断是否足够增加协助次数
//        if (newUseEnergyAddHelpNumCount >= useEnergyNum) {
//            newUseEnergyAddHelpNumCount = newUseEnergyAddHelpNumCount - useEnergyNum;
//            //增加协助次数
//            this.setHelpNum(this.getHelpNum() + addHelpNum);
//        }
//        this.setUseEnergyAddHelpNumCount(newUseEnergyAddHelpNumCount);
//    }
//
//    /**
//     * 消耗协助次数
//     * @return
//     */
//    public boolean consumeHelpNum(int num) {
//        if (this.getHelpNum() <= 0) {
//            return false;
//        }
//        if (this.getHelpNum() < num) {
//            return false;
//        }
//        this.setHelpNum(this.getHelpNum() - num);
//        return true;
//    }

    /**
     * 恢复血量
     * @param rate 总血量的千分比
     */
    public void recoverHp(int rate) {
        //恢复总血量的 rate 千分比
        long addBlood = BigDecimal.valueOf(this.getAllBlood()).multiply(BigDecimal.valueOf(rate)).divide(BigDecimal.valueOf(1000), 8,  RoundingMode.DOWN).longValue();
        this.addBlood(addBlood);
    }

    /**
     * 镇伏地块
     * @param plotData
     * @return
     */
    public SonHaiWinPlotResp winPlot(SonHaiPlotData plotData) {
        //区域配置
        SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(plotData.getRegionId());
        //事件配置
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(plotData.getPlotId());
        //地块所在区域
        SonHaiRegionData regionData = CrossSonHaiActivityMgr.getRegionData(this.getActivityId(), this.getGroupId(), plotData.getTeamId(), plotData.getRegionId());
        int addProgress = 0;
        int extraOpValue = 0;
        if (eventConfig.getEventType() != SonHaiPlotTypeEnum.PLOT_TYPE_13.getType()) {//镇伏兽蛋不给寻踪进度
            addProgress = eventConfig.getSchedule();//镇伏增加的寻踪进度
            //额外的寻踪进度
            int opValue = this.getProgressOpValue(plotData.getX(), plotData.getY());//加成值
            int opRate = this.getProgressOpRate(regionData);//加成率
            extraOpValue = this.countExtraProgress(addProgress, opRate, opValue);
            //计算最终增加的寻踪进度
            addProgress += extraOpValue;
            if (addProgress < 0) {
                addProgress = 0;
            }
        }
        //镇伏地块
        if (regionData != null) {
            int oldProgress = regionData.getProgress();
            regionData.winPlot(plotData.getX(), plotData.getY(), addProgress);
            //判断寻踪进度是否达到，兽王出现
            if (oldProgress < floorConfig.getNeedSchedule() && regionData.getProgress() >= floorConfig.getNeedSchedule()) {
                for (CrossSonHaiUser member : this.getTeam().getMemberMap().values()) {
                    //同步队友兽王红点
                    member.syncRedDotMsg(SonHaiRedDotTypeEnum.TYPE_NULL, SonHaiRedDotTypeEnum.TYPE_NULL, SonHaiRedDotTypeEnum.TYPE_HAVE);
                }
            }
        } else {
            logger.error("山海伏兽-镇伏地块-区域为空：{}", JSONObject.toJSONString(plotData));
        }
        //奖励
        SonHaiWinPlotResp resp = new SonHaiWinPlotResp();
        Property rewardProp = PropertyHelper.parseNewStringToProperty(eventConfig.getReward());//镇伏奖励
        String reward = PropertyHelper.parsePropertyToString(rewardProp);//镇伏奖励
        //判断地块是不是自己的
        if (this.getUserId() == plotData.getUserId()) {
            //奖励
            plotData.setGetRewardFlag(SonHaiRewardFlagEnum.GET_YES.getType());
            resp.setReward(reward);
        } else {
            //奖励存储，领取的时候给
            plotData.setReward(reward);
        }
        //山海灵气 = 该积分为基础山海灵气 * 体力消耗倍率
        long auraScore = eventConfig.getPvpScore() * floorConfig.getEnergy();
        resp.setAddProgress(addProgress);
        resp.setExtraAddProgress(extraOpValue);
        resp.setAddAuraScore(auraScore);
        return resp;
    }




    /**
     * 被打死
     * @param targetUserId 打死我的玩家ID
     * @param plotData 在哪个地块被打死
     * @return 悬赏山海灵气
     */
    public SonHaiUserDieResp die(long targetUserId, SonHaiPlotData plotData) {
        //清除被攻击
        for (SonHaiPlotData attackMeUserPlot : this.attackMeUserPlotMap.values()) {
            if (plotData != attackMeUserPlot) {
                //其他指向该玩家的地块，自动镇伏，无奖励
                attackMeUserPlot.setWinFlag(SonHaiWinFlagEnum.WIN_YES.getType());
                attackMeUserPlot.setWinTime(System.currentTimeMillis());
                attackMeUserPlot.setGetRewardFlag(SonHaiRewardFlagEnum.GET_YES.getType());
            }
        }
        this.attackMeUserPlotMap.clear();
        //pvp击杀次数清0
        int pvpKillNum = this.getPvpKillNum();
        this.setPvpKillNum(0);
        //pvp可被攻击次数-1
        this.setPvpCanBeAttNum(this.getPvpCanBeAttNum() - 1);
        //基础扣除的山海灵气
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(plotData.getPlotId());
        //悬赏山海灵气,算法读配置
        long offerAuraScore = (long) pvpKillNum * this.sonHaiConfig.getPvpKillStreakScore();
        long reAuraScore = eventConfig.getPvpScore() + offerAuraScore;
        if (reAuraScore > 0) {
            //减少山海灵气 = 基础扣除的山海灵气 + 悬赏山海灵气
            CrossSonHaiTeam team = this.getTeam();
            team.changeAuraScore(this, -reAuraScore);
        }
        //记录死亡状态
        this.setDieFlag(SonHaiDieFlagEnum.DIE_YES.getType());
        SonHaiUserDieData dieData = new SonHaiUserDieData(targetUserId, reAuraScore);
        this.setDieData(dieData);
        //死亡日志
        LogCrossSonHaiUserDie log = new LogCrossSonHaiUserDie(
                this.getActivityId(),
                this.getGroupId(),
                this.getUserId(),
                this.getTeamId(),
                targetUserId,
                reAuraScore
        );
        CrossAutoLogMgr.add(log);
        //返回结果
        SonHaiUserDieResp resp = new SonHaiUserDieResp();
        resp.setLoseAuraScore(reAuraScore);
        resp.setOffAuraScore(offerAuraScore);
        return resp;
    }

    /**
     * 重置血量
     */
    public void resetBlood() {
        this.setReBlood(0);
        this.setReBloodInfoMap(new ConcurrentHashMap<>());
        //重新计算总血量
        long allBlood = this.getPowerForPvp();
        this.setAllBlood(allBlood);
    }

    /**
     * 唤醒
     */
    public void wakeUp() {
        //恢复血量
        this.resetBlood();
        //死亡状态变更
        this.setDieFlag(SonHaiDieFlagEnum.DIE_NOT.getType());
        this.setDieData(null);
    }

    /*******************************************************BUFF相关************************************************/

    /**
     * 圣兽降临
     */
    public void buffCome(int reEnergy) {
        //下一次圣兽降临需要消耗的体力
        int buffComeNeedEnergy = this.getNextBuffComeNeedEnergy();
        if (reEnergy >= buffComeNeedEnergy) {
            if (buffComeNeedEnergy <= 0) {
                return;
            }
            //溢出的体力
            int resideEnergy = reEnergy - buffComeNeedEnergy;
            //触发圣兽降临
            Set<Integer> fullLevelBuffIdSet = this.getFullLevelBuffIdSet();//满级buff
            Set<Integer> waitSelectBuffs = this.sonHaiConfig.getBuffSelectSet(this.getRegionId(), fullLevelBuffIdSet);//获取3个待选择的buff
            //注入玩家buff待选择列表
            this.addWaitSelectBuff(waitSelectBuffs);
            //圣兽降临次数加1
            this.setBuffComeNum(this.getBuffComeNum() + 1);

            //获取下一次圣兽降临所需要的体力
            int nextBuffComeNeedEnergy = this.sonHaiConfig.getBuffComeNeedEnergy(this.getBuffComeNum() + 1);
            this.setNextBuffComeNeedEnergy(nextBuffComeNeedEnergy);

            //溢出的体力是否能继续圣兽降临
            if (resideEnergy >= nextBuffComeNeedEnergy) {
                //继续圣兽降临（递归）
                this.buffCome(resideEnergy);
            } else {
                //下一次圣兽降临需要的体力 - 移除的体力
                this.setNextBuffComeNeedEnergy(nextBuffComeNeedEnergy - resideEnergy);
            }
        } else {
            //下一次圣兽降临需要的体力
            this.setNextBuffComeNeedEnergy(buffComeNeedEnergy - reEnergy);
        }
    }

    /**
     * 获取满级buff id集合
     * @return
     */
    private Set<Integer> getFullLevelBuffIdSet() {
        Set<Integer> fullLevelBuffIdSet = new HashSet<>();
        for (SonHaiBuffData buffData : this.getBuffMap().values()) {
            if (buffData.getBuffId() > 0) {
                SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData.getBuffId());
                if (buffData.getLevel() >= buffConfig.getNum()) {
                    fullLevelBuffIdSet.add(buffData.getBuffId());
                }
            }
        }
        return fullLevelBuffIdSet;
    }

    /**
     * 重新随机待选择BUFF LIST
     * @return
     * @throws BusinessException
     */
    public void resetRandomSelectBuff() throws BusinessException {
        if (this.getWaitSelectBuffList().isEmpty()) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_WAIT_SELECT_BUFF_NOT_FOUND);
        }
        //获取当前，待选择的buff
        SonHaiWaitSelectBuffData waitBuffData = this.getWaitSelectBuffList().get(0);
        //判断是否重随过
        if (waitBuffData.getResetRandomNum() > 0) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_ALREADY_REST_BUFF);
        }
        //重新随机出3个待选择的buff
        Set<Integer> fullLevelBuffIdSet = this.getFullLevelBuffIdSet();//满级buff
        Set<Integer> waitSelectBuffs = this.sonHaiConfig.getBuffSelectSet(this.getRegionId(), fullLevelBuffIdSet);
        waitBuffData.setWaitSelectBuffSet(waitSelectBuffs);
        waitBuffData.setResetRandomNum(waitBuffData.getResetRandomNum() + 1);
        setUpdateOption();
    }

    /**
     * 选择BUFF
     * @param buffId
     * @return 操作类型
     * @throws BusinessException
     */
    public void selectBuff(int buffId) throws BusinessException {
        //判断待选择列表是否存在
        if (this.getWaitSelectBuffList().isEmpty()) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_WAIT_SELECT_BUFF_NOT_FOUND);
        }
        Set<Integer> waitBuffSet = this.getWaitSelectBuffList().get(0).getWaitSelectBuffSet();
        //判断buff是否在待选择列表中
        if (!waitBuffSet.contains(buffId)) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_SELECT_BUFF_NOT_INT_WAIT_LIST);
        }
        //buff配置
        SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffId);
        if (buffConfig == null) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_BUFF_NOT_FOUND);
        }
        //获取buff
        SonHaiBuffData myBuffData = this.getBuff(buffId);
        //判断buff是否已经满级
        if (myBuffData != null && myBuffData.getLevel() >= buffConfig.getNum()) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_BUFF_MAX_LEVEL);
        }
        if (myBuffData == null) {
            myBuffData = new SonHaiBuffData();
            myBuffData.setBuffId(buffId);
            myBuffData.setLevel(0);
            this.addBuff(myBuffData);
        }
        //升级
        myBuffData.setLevel(myBuffData.getLevel() + 1);
        //移除
        this.getWaitSelectBuffList().remove(0);

        //2024-08-27,重新随机第一个buff,保证待选择的buff都是合法的
        if (!this.getWaitSelectBuffList().isEmpty()) {
            //第一个buff
            SonHaiWaitSelectBuffData waitBuffData = this.getWaitSelectBuffList().get(0);
            //重新随机出3个待选择的buff
            Set<Integer> fullLevelBuffIdSet = this.getFullLevelBuffIdSet();//满级buff
            Set<Integer> waitSelectBuffs = this.sonHaiConfig.getBuffSelectSet(this.getRegionId(), fullLevelBuffIdSet);
            //注入重随的buff
            waitBuffData.setWaitSelectBuffSet(waitSelectBuffs);
        }
        //设置更新
        this.setUpdateOption();
    }

    /**
     * 同步玩家数据
     */
    public void syncUserData(boolean syncRedDot) {
        if (this.getRegionData() != null) {
            SonHaiProto.SonHaiUserDataSimple.Builder builder = SonHaiActivityPb.buildSonHaiUserDataSimple(this, syncRedDot);
            MessageHelper.sendPacket(this.getServerId(), this.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_SYNC_USER_DATA, builder));
        }
    }

    /**
     * 是否可打兽王
     * @return
     */
    public boolean checkCanBattleBoss() {
        if (this.regionData != null) {
            if (this.regionData.getBeastBoss().getWinFlag() == SonHaiWinFlagEnum.WIN_NOT.getType()) {
                SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(this.regionData.getRegionId());
                if (this.regionData.getProgress() >= floorConfig.getNeedSchedule()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 消耗协助次数
     * @return
     */
    public boolean consumeHelpNum(int num) {
        if (this.getHelpNum() <= 0) {
            return false;
        }
        if (this.getHelpNum() < num) {
            return false;
        }
        this.setHelpNum(this.getHelpNum() - num);
        return true;
    }

    /**
     * 增加【每消耗N1体力恢复N2协助次数】计数
     *
     * @param energyNum
     */
    public void addUseEnergyAddHelpNumCount(int energyNum) {
        //读取配置【每消耗N1体力恢复N2协助次数】
        int useEnergyNum = this.sonHaiConfig.getCostEnergyHelpNum().get(0);//读配置 N1
        int addHelpNum = this.sonHaiConfig.getCostEnergyHelpNum().get(1);//都配置 N2
        //新计数
        int newUseEnergyAddHelpNumCount = this.getHelpNumCount() + energyNum;
        //判断是否足够增加协助次数
        if (newUseEnergyAddHelpNumCount >= useEnergyNum) {
            newUseEnergyAddHelpNumCount = newUseEnergyAddHelpNumCount - useEnergyNum;
            //增加协助次数
            this.setHelpNum(this.getHelpNum() + addHelpNum);
        }
        this.setHelpNumCount(newUseEnergyAddHelpNumCount);
    }

    /**
     * 领取地块镇伏奖励
     * @param x
     * @param y
     * @return
     * @throws BusinessException
     */
    public SonHaiRewardResp receiveWinReward(int x, int y) throws BusinessException {
        //获取地块
        SonHaiPlotData plotData = this.regionData.getPlotData(x, y);
        if (plotData == null) {
            throw new BusinessException(GameErrorCode.E_SON_HAI_PLOT_NOT_FOUND);
        }
        //判断地块是否被镇伏
        if (plotData.getWinFlag() != SonHaiWinFlagEnum.WIN_YES.getType()) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_PLOT_NOT_WIN);
        }
        //判断地块是否属于自己
        if (plotData.getUserId() != this.getUserId()) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_PLOT_NOT_ME);
        }
        //判断地块奖励是否已经领取过
        if (plotData.getGetRewardFlag() != SonHaiRewardFlagEnum.GET_NOT.getType()) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_REWARD_ALREADY_RECEIVE);
        }
        //判断奖励是否存在
        if (StringUtils.isNullOrEmpty(plotData.getReward())) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_EGG_REWARD_NOT_FOUND);
        }
        //领取
        plotData.setGetRewardFlag(SonHaiRewardFlagEnum.GET_YES.getType());
        //奖励
        String reward = plotData.getReward();
        //山海灵气
        long addAuraScore = plotData.getExtraAuraScore();
        //返回
        SonHaiRewardResp resp = new SonHaiRewardResp();
        resp.setReward(reward);
        resp.setAddAuraScore(addAuraScore);
        return resp;
    }

    /**
     * 领取兽王镇伏奖励
     * @return
     * @throws BusinessException
     */
    public SonHaiRewardResp receiveBossWinReward(SonHaiRegionData regionData) throws BusinessException {
        SonHaiBeastBossData boss = regionData.getBeastBoss();
        //判断boss是否存在
        if (boss == null) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_BEAST_BOSS_NOT_FOUND);
        }
        //判断是否被镇伏
        if (boss.getWinFlag() != SonHaiWinFlagEnum.WIN_YES.getType()) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_PLOT_NOT_WIN);
        }
        //判断奖励是否已经领取过
        if (boss.getRewardUserIdSet().contains(this.getUserId())) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_REWARD_ALREADY_RECEIVE);
        }
        List<SonHaiPlotData> bossPlotList = regionData.getBossPlotDataList();
        if (bossPlotList == null || bossPlotList.isEmpty()) {
            throw BusinessException.newException(GameErrorCode.E_SON_HAI_BOSS_PLOT_NOT_EXIST);
        }
        //领取
        boss.addRewardUserIdSet(this.getUserId());
        regionData.setUpdateOption();
        //事件配置
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(boss.getEventId());
        //奖励
        Property rewardProp = PropertyHelper.parseNewStringToProperty(eventConfig.getReward());//镇伏奖励
        String reward = PropertyHelper.parsePropertyToString(rewardProp);//镇伏奖励
        //山海灵气
        long baseAddAuraScore = eventConfig.getPvpScore();
        int auraScoreOpRate = this.getAuraScoreOpRate(bossPlotList.get(0), true);//buff:山海灵气加成率
        long auraScoreOpValue = this.getAuraScoreOpValue(bossPlotList.get(0), true);//buff:山海灵气加成值
        long addAuraScore = this.countAureScore(baseAddAuraScore, auraScoreOpRate, auraScoreOpValue);
        //返回
        SonHaiRewardResp resp = new SonHaiRewardResp();
        resp.setReward(reward);
        resp.setAddAuraScore(addAuraScore);
        return resp;
    }

    /**
     * 击杀玩家后处理
     */
    private void pvpKillHandle(SonHaiPlotData plotData) {
        //区域配置
        SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(plotData.getRegionId());
        int energy;
        if (floorConfig != null && floorConfig.getEnergy() > 0) {
            energy = floorConfig.getEnergy();
        } else {
            energy = 1;
        }
        //pvp击杀次数 + 1
        int newPvpKillNum = this.getPvpKillNum() + energy;
        this.setPvpKillNum(newPvpKillNum);
        //pvp可被攻击次数 +1
        int newPvpCanBeAttNum = this.getPvpCanBeAttNum() + energy;
        this.setPvpCanBeAttNum(newPvpCanBeAttNum);
    }

    /**
     * 发送协助信息到聊天框
     * @param plotData
     */
    private void sendTeamChatMsg(SonHaiPlotData plotData) {
        int groupId = this.getGroupId();
        //没镇伏，推送协助信息到队伍聊天
        CommonTeamProto.CommonTeamChatMsg.Builder teamChatMsg = CommonTeamMgr.createTeamChatMsg(this.getActivityId(), groupId, this.getUserId(),  CommonTeamProto.CommonTeamChatTypeEnum.HELP_VALUE, eChatContentType.Common.getContentType(), null);
        if (teamChatMsg != null) {
            teamChatMsg.setPlotData(SonHaiActivityPb.buildSonHaiChatMsgPlotData(plotData));
            CommonTeamMgr.sendTeamChatMsg(this.getActivityId(), groupId, this.getUserId(), teamChatMsg);
        }
    }

    /**
     * 随机获取一个队友
     * @return
     */
    private CrossSonHaiUser randomHelpMember(SonHaiRegionData regionData, boolean pveFlag) {
        CrossSonHaiTeam team = this.getTeam();
        if (team.getMemberMap().size() <= 1) {
            return null;
        }
        Set<Long> memberIdSet = new HashSet<>();
        long maxPowerUserId = 0;//最大战力玩家
        long maxPower = 0;
        for (CrossSonHaiUser member : team.getMemberMap().values()) {
            if (member.getUserId() != this.getUserId()) {
                memberIdSet.add(member.getUserId());
                long memberPower;
                if (pveFlag) {
                    memberPower = member.getPowerForPve(regionData);
                } else {
                    memberPower = member.getPowerForPvp();
                }
                if (memberPower > maxPower) {
                    maxPower = memberPower;
                    maxPowerUserId = member.getUserId();
                }
            }
        }
        //触发队友协战时，最高战力队友的出战概率提升
        int maxPowerUserAddRate = this.randomMaxPowerHelpAddRateFromBuff();

        //1000权重，分配
        int weight = 1000 / memberIdSet.size();
        Map<Long, Integer> wMap = new HashMap<>();
        for (long memberId : memberIdSet) {
            if (memberId == maxPowerUserId) {
                BigDecimal rate = BigDecimal.valueOf(maxPowerUserAddRate).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
                int addWeight = BigDecimal.valueOf(weight).multiply(rate).intValue();
                wMap.put(memberId, weight + addWeight);
            } else {
                wMap.put(memberId, weight);
            }
        }
        //按权重，随机出一个队友
        long memberUserId = RandomHelper.getRandomKeyByWeightForKeyLong(wMap);
        return team.getMemberMap().get(memberUserId);
    }

    /*******************************************************战斗处理***********************************************/

    /**
     * pve战斗
     * @param regionData
     * @param plotData
     * @return
     */
    public SonHaiNewBattleResp doPveBattle(SonHaiRegionData regionData, SonHaiPlotData plotData) {
        SonHaiNewBattleResp resp = new SonHaiNewBattleResp();
        boolean winFlag;
        long damage = 0;
        long realDamage = 0;
        //战斗
        SonHaiBattleOneResp battleOneResp = this.pveBattleOne(plotData.getBeastData(), regionData, plotData, 0);
        resp.setBattleOneResp(battleOneResp);
        damage += battleOneResp.getDamage();
        realDamage += battleOneResp.getRealDamage();
        winFlag = battleOneResp.isWinFlag();
        //没打死，随机出队友
        if (!winFlag) {
            CrossSonHaiUser member = this.randomHelpMember(regionData, true);
            if (member != null) {
                resp.setMemberId(member.getUserId());
                //队友协助打一下
                SonHaiBattleOneResp helpBattleOneResp = member.pveBattleOne(plotData.getBeastData(), regionData, plotData, this.getUserId());
                resp.setMemberBattleOneResp(helpBattleOneResp);
                damage += helpBattleOneResp.getDamage();
                realDamage += helpBattleOneResp.getRealDamage();
                winFlag = helpBattleOneResp.isWinFlag();
            }
        }
        resp.setWinFlag(winFlag);//是否镇伏
        resp.setDamage(damage);//我和队友的总伤害
        resp.setRealDamage(realDamage);//我和队友的真实伤害

        //原寻踪进度
        int oldProgress = regionData.getProgress();
        //事件配置
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(plotData.getPlotId());
        //判断是否战斗胜利
        if (resp.isWinFlag()) {
            //镇伏
            SonHaiWinPlotResp winPlotResp = this.winPlot(plotData);
            resp.setReward(winPlotResp.getReward());
            resp.setAddProgress(winPlotResp.getAddProgress());
            resp.setProgressAddValue(winPlotResp.getExtraAddProgress());
            //山海灵气
            long baseAddAuraScore = winPlotResp.getAddAuraScore();
            int auraScoreOpRate = this.getAuraScoreOpRate(plotData, true);//buff:山海灵气加成率
            long auraScoreOpValue = this.getAuraScoreOpValue(plotData, true);//buff:山海灵气加成值
            long addAuraScore = this.countAureScore(baseAddAuraScore, auraScoreOpRate, auraScoreOpValue);
            //判断是自己的地块
            if (this.getUserId() == plotData.getUserId()) {
                resp.setAddAuraScore(addAuraScore);
                resp.setAuraScoreAddRate(auraScoreOpRate);
                resp.setAuraScoreAddValue(auraScoreOpValue);
            } else {
                //山海灵气，存起来。领取奖励的时候给
                plotData.setExtraAuraScore(addAuraScore);
            }
            //恢复体力buff
            int recoverHp = this.recoverHpFromBuff();
            resp.setRecoverHp(recoverHp);
        } else {
            //没镇伏，推送协助信息到队伍聊天。推送条件：1.自己的地块，2.第一次打
            int attNum = plotData.getAttNum(this.getUserId());
            if (this.getUserId() == plotData.getUserId() && attNum == 0) {
                this.sendTeamChatMsg(plotData);
            }
        }
        //地块增加玩家攻击次数
        plotData.addAttNum(this.getUserId());
        //增加积分
        long allScore = this.sonHaiConfig.getEventAllScore(plotData.getRegionId(), plotData.getPlotId());//总积分
        int scoreOpRate = this.getScoreOpRate(regionData, plotData.getX(), plotData.getY(), resp.isWinFlag(), plotData.getLevel(), oldProgress);//积分buff加减益比例
        long scoreOpValue = this.getScoreOpValue(resp.isWinFlag(), eventConfig.getSchedule());//积分buff加减益值
        long addScore = this.addScoreByRealDamage(allScore, plotData.getBeastData().getAllBlood(), resp.getRealDamage(), scoreOpRate, scoreOpValue);//增加积分
        resp.addScore(addScore);
        resp.setScoreAddRate(scoreOpRate);
        resp.setScoreAddValue(scoreOpValue);
        //战斗后处理
        this.afterBattle();
        return resp;
    }

    /**
     * pve战斗-one by one
     * @param beastData 异兽
     * @param regionData 区域
     * @param plotData 涉及的地块
     * @return
     */
    private SonHaiBattleOneResp pveBattleOne(SonHaiBeastData beastData, SonHaiRegionData regionData, SonHaiPlotData plotData, long beHelpUserId) {
        List<SonHaiXYData> plots = new ArrayList<>();
        plots.add(new SonHaiXYData(plotData.getX(), plotData.getY()));
        return this.pveBattleOne(beastData, regionData, plots, beHelpUserId);
    }

    /**
     * pve战斗-one by one
     * @param beastData 异兽
     * @param regionData 区域
     * @param plots 战斗涉及的地块
     * @return
     */
    private SonHaiBattleOneResp pveBattleOne(SonHaiBeastData beastData, SonHaiRegionData regionData, List<SonHaiXYData> plots, long beHelpUserId) {
        //获取门客战力
        long myPower = this.getPowerForPve(regionData);//计算加成后的战力

        //异兽战力加成
        int beatsPowerAddRate = regionData.getPlotBeatsBattlePowerAddRateForMul(plots, this.sonHaiConfig);
        //战力加成比例
        BigDecimal beatsPowerAddRateBig = BigDecimal.valueOf(beatsPowerAddRate + 1000).divide(BigDecimal.valueOf(1000), 8,  RoundingMode.DOWN);
        //异兽总战力
        long beastConfigPower = beastData.getAllBlood();
        //加成后的总战力
        long beastTotalPower = BigDecimal.valueOf(beastConfigPower).multiply(beatsPowerAddRateBig).longValue();
        //异兽当前战力
        long beastRealPower = beastData.getBlood();
        //加成后的当前战力
        long beastPower = BigDecimal.valueOf(beastRealPower).multiply(beatsPowerAddRateBig).longValue();

        //战斗结果
        boolean winFlag = myPower >= beastPower;

        //异兽掉血
        long damage;
        if (winFlag) {
            damage = beastPower;
        } else {
            damage = myPower;
        }
        //真实伤害 = 真实总血量 * 伤害比
        long realDamage = BigDecimal.valueOf(beastConfigPower).multiply(BigDecimal.valueOf(damage)).divide(BigDecimal.valueOf(beastTotalPower), 8,  RoundingMode.DOWN).longValue();
        //对方伤害
        if (beHelpUserId > 0) {
            beastData.addReBlood(beHelpUserId, damage, realDamage);//自动协助，伤害记录在被协助的玩家上
        } else {
            beastData.addReBlood(this.getUserId(), damage, realDamage);
        }

        //返回
        SonHaiBattleOneResp resp = new SonHaiBattleOneResp();
        resp.setMyPower(myPower);
        resp.setTargetPower(beastPower);
        resp.setTargetTotalPower(beastTotalPower);
        resp.setRealDamage(realDamage);
        resp.setDamage(damage);
        resp.setWinFlag(winFlag);
        return resp;
    }

    /**
     * pvp战斗
     * @param regionData 区域
     * @param plotData 地块
     * @param targetUser 目标玩家
     * @return
     */
    public SonHaiNewBattleResp doPvpBattle(SonHaiRegionData regionData, SonHaiPlotData plotData, CrossSonHaiUser targetUser) {
        SonHaiNewBattleResp resp = new SonHaiNewBattleResp();
        boolean winFlag;
        long damage = 0;
        long reamDamage = 0;
        //战斗
        SonHaiBattleOneResp battleOneResp = this.pvpBattleOne(targetUser, 0);
        resp.setBattleOneResp(battleOneResp);
        damage += battleOneResp.getDamage();
        reamDamage += battleOneResp.getRealDamage();
        winFlag = battleOneResp.isWinFlag();
        //随机出队友
        if (!winFlag) {
            CrossSonHaiUser member = this.randomHelpMember(regionData, false);
            if (member != null) {
                resp.setMemberId(member.getUserId());
                //队友协助打一下
                SonHaiBattleOneResp helpBattleOneResp = member.pvpBattleOne(targetUser, this.getUserId());
                resp.setMemberBattleOneResp(helpBattleOneResp);
                damage += helpBattleOneResp.getDamage();
                reamDamage += helpBattleOneResp.getRealDamage();
                winFlag = helpBattleOneResp.isWinFlag();
            }
        }
        resp.setWinFlag(winFlag);//是否镇伏
        resp.setDamage(damage);//我和队友的总伤害
        resp.setRealDamage(reamDamage);//我和队友的真实伤害

        //原寻踪进度
        int oldProgress = regionData.getProgress();
        //事件
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(plotData.getPlotId());
        //判断是否战斗胜利
        SonHaiUserDieData dieData = null;
        if (resp.isWinFlag()) {
            //镇伏
            SonHaiWinPlotResp winPlotResp = this.winPlot(plotData);
            resp.setReward(winPlotResp.getReward());
            resp.setAddProgress(winPlotResp.getAddProgress());
            resp.setProgressAddValue(winPlotResp.getExtraAddProgress());
            //击杀玩家后处理
            this.pvpKillHandle(plotData);
            //玩家死亡
            SonHaiUserDieResp dieResp = targetUser.die(this.getUserId(), plotData);
            resp.setLoseAuraScore(dieResp.getLoseAuraScore());
            //山海灵气
            long baseAddAuraScore = winPlotResp.getAddAuraScore() + dieResp.getOffAuraScore();
            int auraScoreOpRate = this.getAuraScoreOpRate(plotData, true);//buff:山海灵气加成率
            long auraScoreOpValue = this.getAuraScoreOpValue(plotData, true);//buff:山海灵气加成值
            long addAuraScore = this.countAureScore(baseAddAuraScore, auraScoreOpRate, auraScoreOpValue);
            if (this.getUserId() == plotData.getUserId()) {
                resp.setAddAuraScore(addAuraScore);
                resp.setAuraScoreAddRate(auraScoreOpRate);
                resp.setAuraScoreAddValue(auraScoreOpValue);
            } else {
                //山海灵气，存起来。领取奖励的时候给
                plotData.setExtraAuraScore(addAuraScore);
            }
            //死亡信息
            dieData = new SonHaiUserDieData();
            dieData.setTargetUserId(this.getUserId());
            dieData.setReAureScore(dieResp.getLoseAuraScore());
            dieData.setDieTime(System.currentTimeMillis());
        } else {
            //没镇伏，推送协助信息到队伍聊天。推送条件：1.自己的地块，2.第一次打
            int attNum = plotData.getAttNum(this.getUserId());
            if (this.getUserId() == plotData.getUserId() && attNum == 0) {
                this.sendTeamChatMsg(plotData);
            }
        }

        //推送玩家被打
        targetUser.syncUserBeAtt(dieData);

        //地块增加玩家攻击次数
        plotData.addAttNum(this.getUserId());
        //增加积分
        long allScore = this.sonHaiConfig.getEventAllScore(plotData.getRegionId(), plotData.getPlotId());//总积分
        int scoreOpRate = this.getScoreOpRate(regionData, plotData.getX(), plotData.getY(), resp.isWinFlag(), plotData.getLevel(), oldProgress);//积分buff加减益比例
        long scoreOpValue = this.getScoreOpValue(resp.isWinFlag(), eventConfig.getSchedule());//积分buff加减益值
        long addScore = this.addScoreByRealDamage(allScore, targetUser.getAllBlood(), resp.getRealDamage(), scoreOpRate, scoreOpValue);//增加积分
        resp.setAddScore(addScore);
        resp.setScoreAddRate(scoreOpRate);
        resp.setScoreAddValue(scoreOpValue);
        //战斗后处理
        this.afterBattle();
        return resp;
    }

    /**
     * pvp战斗-one by one
     * @param targetUser
     * @return
     */
    public SonHaiBattleOneResp pvpBattleOne(CrossSonHaiUser targetUser, long beHelpUserId) {
        //我方战力
        long myPower = this.getPowerForPvp();
        //对方战力
        long targetPower = targetUser.getBlood();
        //战斗结果
        boolean winFlag = myPower >= targetPower;
        //对方掉血
        long damage;
        if (winFlag) {
            damage = targetPower;
        } else {
            damage = myPower;
        }
        //对方掉血
        if (beHelpUserId > 0) {
            targetUser.addReBlood(beHelpUserId, damage);
        } else {
            targetUser.addReBlood(this.getUserId(), damage);
        }
        //返回
        SonHaiBattleOneResp resp = new SonHaiBattleOneResp();
        resp.setMyPower(myPower);
        resp.setTargetPower(targetPower);
        resp.setTargetTotalPower(targetUser.getAllBlood());
        resp.setRealDamage(damage);
        resp.setDamage(damage);
        resp.setWinFlag(winFlag);
        return resp;
    }

    /**
     * 推送玩家被打
     * @param dieData
     */
    private void syncUserBeAtt(SonHaiUserDieData dieData) {
        //推送玩家被打
        SonHaiProto.SonHaiSyncUserDieMsg.Builder msg = SonHaiProto.SonHaiSyncUserDieMsg.newBuilder();
        msg.setActivityId(this.getActivityId());
        if (dieData != null) {
            msg.setDieData(SonHaiActivityPb.buildSonHaiUserDieData(dieData));
        }
        msg.setAllBlood(this.getAllBlood());
        msg.setReBlood(this.getReBlood());
        MessageHelper.sendPacket(this.getServerId(), this.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_SYNC_USER_DIE, msg));
    }

    /**
     * boss战斗
     * @param bossData
     * @return
     */
    public SonHaiNewBattleResp doBossBattle(SonHaiBeastBossData bossData, SonHaiRegionData regionData) {
        SonHaiNewBattleResp resp = new SonHaiNewBattleResp();
        boolean winFlag;
        long damage = 0;
        long realDamage = 0;
        //打boss
        SonHaiBattleOneResp battleOneResp = this.pveBattleOne(bossData.getBeastData(), regionData, bossData.getPositionList(), 0);
        resp.setBattleOneResp(battleOneResp);
        damage += battleOneResp.getDamage();
        realDamage += battleOneResp.getRealDamage();
        winFlag = battleOneResp.isWinFlag();
        //随机出队友
        if (!winFlag) {
            CrossSonHaiUser member = this.randomHelpMember(regionData, true);
            if (member != null) {
                resp.setMemberId(member.getUserId());
                //队友协助打一下
                SonHaiBattleOneResp helpBattleOneResp = member.pveBattleOne(bossData.getBeastData(), regionData, bossData.getPositionList(), this.getUserId());
                resp.setMemberBattleOneResp(helpBattleOneResp);
                damage += helpBattleOneResp.getDamage();
                realDamage += helpBattleOneResp.getRealDamage();
                winFlag = helpBattleOneResp.isWinFlag();
            }
        }
        resp.setWinFlag(winFlag);//是否镇伏
        resp.setDamage(damage);//我和队友的总伤害
        resp.setRealDamage(realDamage);//我和队友的真实伤害

        //原寻踪进度
        int oldProgress = regionData.getProgress();
        //boss事件配置
        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(bossData.getEventId());
        //是否镇伏
        if (resp.isWinFlag()) {
            bossData.setWinFlag(SonHaiWinFlagEnum.WIN_YES.getType());
            bossData.addRewardUserIdSet(this.getUserId());
            regionData.setUpdateOption();
            //镇伏4个兽王地块
            List<SonHaiPlotData> plotList = regionData.getPlotTypeDataMap().get(SonHaiPlotTypeEnum.PLOT_TYPE_1.getType());
            for (SonHaiPlotData plotData : plotList) {
                plotData.setWinFlag(SonHaiWinFlagEnum.WIN_YES.getType());
                plotData.setWinTime(System.currentTimeMillis());
            }
            //boss镇伏奖励
            Property rewardProp = PropertyHelper.parseNewStringToProperty(eventConfig.getReward());
            String reward = PropertyHelper.parsePropertyToString(rewardProp);
            resp.setReward(reward);

            //山海灵气
            long baseAddAuraScore = eventConfig.getPvpScore();
            int auraScoreOpRate = this.getAuraScoreOpRate(plotList.get(0), true);//buff:山海灵气加成率
            long auraScoreOpValue = this.getAuraScoreOpValue(plotList.get(0), true);//buff:山海灵气加成值
            long addAuraScore = this.countAureScore(baseAddAuraScore, auraScoreOpRate, auraScoreOpValue);
            resp.setAddAuraScore(addAuraScore);
            resp.setAuraScoreAddRate(auraScoreOpRate);
            resp.setAuraScoreAddValue(auraScoreOpValue);

            //兽王被镇伏，推送红点
            for (CrossSonHaiUser member : this.getTeam().getMemberMap().values()) {
                if (member.getUserId() != this.getUserId()) {
                    //同步队友兽王红点
                    member.syncRedDotMsg(SonHaiRedDotTypeEnum.TYPE_NULL, SonHaiRedDotTypeEnum.TYPE_NULL, SonHaiRedDotTypeEnum.TYPE_HAVE);
                }
            }
        }
        //增加攻击次数
        bossData.addAttNum(this.getUserId());
        //积分增加
        long allScore = this.sonHaiConfig.getEventAllScore(bossData.getRegionId(), bossData.getEventId());//总积分
        int scoreOpRate = this.getScoreOpRate(regionData, bossData.getPositionList(), resp.isWinFlag(), eventConfig.getLevel(), oldProgress, true);//积分buff加减益比例
        long scoreOpValue = this.getScoreOpValue(resp.isWinFlag(), eventConfig.getSchedule());
        long addScore = this.addScoreByRealDamage(allScore, bossData.getBeastData().getAllBlood(), resp.getRealDamage(), scoreOpRate, scoreOpValue);
        resp.setScoreAddRate(scoreOpRate);
        resp.setAddScore(addScore);
        resp.setScoreAddValue(scoreOpValue);
        //战斗后处理
        this.afterBattle();
        regionData.setUpdateOption();
        return resp;
    }

    /**
     * egg战斗
     * @param myPatronsMap
     * @param plotData
     * @param eggData
     * @return
     */
    public SonHaiBattleResp doEggBattle(Map<Integer, SonHaiPatronsData> myPatronsMap, SonHaiRegionData regionData, SonHaiPlotData plotData, SonHaiEggData eggData, CrossSonHaiUser targetUser) {
        //战斗
        SonHaiBattleResp resp = this.eggBattle(myPatronsMap, eggData, regionData, plotData);
//        //蛋易主前的血量
//        long allBlood = eggData.getAllBlood();
//        //原寻踪进度
//        int oldProgress = regionData.getProgress();
//        //事件
//        SonHaiEventConfig eventConfig = this.sonHaiConfig.getEventConfig(plotData.getPlotId());
        //判断是否胜利
        if (resp.isWinFlag()) {
            //镇伏
            SonHaiWinPlotResp winPlotResp = this.winPlot(plotData);
            resp.setReward(winPlotResp.getReward());
//            resp.setAddProgress(winPlotResp.getAddProgress());
//            resp.setProgressAddValue(winPlotResp.getExtraAddProgress());
//            //山海灵气
//            long baseAddAuraScore = winPlotResp.getAddAuraScore();
//            int auraScoreOpRate = this.getAuraScoreOpRate(plotData, true);//buff:山海灵气加成率
//            long auraScoreOpValue = this.getAuraScoreOpValue(plotData, true);//buff:山海灵气加成值
//            long addAuraScore = this.countAureScore(baseAddAuraScore, auraScoreOpRate, auraScoreOpValue);
//            if (this.getUserId() == plotData.getUserId()) {
//                resp.setAddAuraScore(addAuraScore);
//                resp.setAuraScoreAddRate(auraScoreOpRate);
//                resp.setAuraScoreAddValue(auraScoreOpValue);
//            } else {
//                //山海灵气，存起来。领取奖励的时候给
//                plotData.setExtraAuraScore(addAuraScore);
//            }
            //占领兽蛋
            this.occupyEgg(eggData, myPatronsMap, targetUser);
            //清除蛋蛋关联的地块，直接无奖励镇伏这些地块
            List<SonHaiPlotData> needNotifyPlotList = eggData.clearAttackMeUserPlot();
            //推送【蛋被抢走】
            for (SonHaiPlotData needNotifyPlot : needNotifyPlotList) {
                this.pushEggBeTakenMsg(needNotifyPlot, eggData, SonHaiEggPlotLoseTypeEnum.BE_TAKEN);
            }
        } else {
            //没镇伏，推送协助信息到队伍聊天。推送条件：1.自己的地块，2.第一次打
            int attNum = plotData.getAttNum(this.getUserId());
            if (this.getUserId() == plotData.getUserId() && attNum == 0) {
                this.sendTeamChatMsg(plotData);
            }
        }
        //地块增加玩家攻击次数
        plotData.addAttNum(this.getUserId());
//        //积分增加
//        long allScore = this.sonHaiConfig.getEventAllScore(plotData.getRegionId(), plotData.getPlotId());//总积分
//        int scoreOpRate = this.getScoreOpRate(regionData, plotData.getX(), plotData.getY(), resp.isWinFlag(), plotData.getLevel(), oldProgress);//积分buff加减益比例
//        long scoreOpValue = this.getScoreOpValue(resp.isWinFlag(), eventConfig.getSchedule());
//        long addScore = this.addScoreByRealDamage(allScore, allBlood, resp.getRealDamage(), scoreOpRate, scoreOpValue);
//        resp.setAddScore(addScore);
//        resp.setScoreAddRate(scoreOpRate);
//        resp.setScoreAddValue(scoreOpValue);
        //战斗后处理
        this.afterBattle();
        return resp;
    }

    /**
     * 占领兽蛋
     * @param eggData
     * @param myPatronsMap
     */
    private void occupyEgg(SonHaiEggData eggData, Map<Integer, SonHaiPatronsData> myPatronsMap, CrossSonHaiUser targetUser) {
        //原门客驻守的兽蛋丢弃
        Map<Integer, SonHaiEggData> giveUpEggMap = new HashMap<>();
        for (SonHaiEggData oldEggData : this.userEggDataMap.values()) {
            for (SonHaiPatronsData patronsData : oldEggData.getPatronsDataMap().values()) {
                if (myPatronsMap.containsKey(patronsData.getPatronsId())) {
                    giveUpEggMap.put(oldEggData.getId(), oldEggData);
                }
            }
        }
        for (SonHaiEggData oldEggData : giveUpEggMap.values()) {
            this.removeOccupyEgg(oldEggData.getId());
            //重置兽蛋
            List<SonHaiPlotData> needNotifyPlotList = oldEggData.reset(false);
            //推送【蛋被丢弃】
            for (SonHaiPlotData needNotifyPlot : needNotifyPlotList) {
                this.pushEggBeTakenMsg(needNotifyPlot, oldEggData, SonHaiEggPlotLoseTypeEnum.BE_GIVE_UP);
            }
        }
        //计算下守蛋血量
        int addRate = this.getPowerAddRateForPvp();
        for (SonHaiPatronsData patronsData : myPatronsMap.values()) {
            long allBlood = this.countPower(patronsData.getAbility(), addRate);
            patronsData.setAllBlood(allBlood);
        }
        eggData.setUserId(this.getUserId());
        eggData.setPatronsDataMap(myPatronsMap);
        eggData.setOccupyTime(System.currentTimeMillis());
        this.userEggDataMap.put(eggData.getId(), eggData);
        //对方玩家清除兽蛋占领
        if (targetUser != null) {
            //清除兽蛋占领
            targetUser.removeOccupyEgg(eggData.getId());
            //推送占领的蛋被抢走
            targetUser.addLostEggMsg(eggData, this.getUserId());
        }
    }

    /**
     * 清除占领的兽蛋
     * @param eggId
     */
    private void removeOccupyEgg(int eggId) {
        this.userEggDataMap.remove(eggId);
    }

    /**
     * 推送蛋被抢走
     * @param plotData
     * @param eggData
     */
    private void pushEggBeTakenMsg(SonHaiPlotData plotData, SonHaiEggData eggData, SonHaiEggPlotLoseTypeEnum loseTypeEnum) {
        SonHaiProto.SonHaiPushEggBeTakenMsg.Builder pushMsg = SonHaiProto.SonHaiPushEggBeTakenMsg.newBuilder();
        //操作玩家
        CrossUserBaseInfo opUserBaseInfo = CrossUserMgr.getCrossUserBaseInfo(this.getUserId());
        //玩家信息
        CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(plotData.getUserId());
        CrossSonHaiUser targetUser = CrossSonHaiActivityMgr.getUser(plotData.getActivityId(), plotData.getGroupId(), plotData.getUserId());
        if (targetUser != null && userBaseInfo != null && opUserBaseInfo != null) {
            pushMsg.setUserInfo(PlayerBasePb.parsePlayerBaseTempMsg(opUserBaseInfo.getUserBaseInfo()));
            pushMsg.setEggData(SonHaiActivityPb.buildSonHaiEggData(eggData, targetUser.getLanguage()));
            pushMsg.setPlot(SonHaiActivityPb.buildSonHaiSimplePlotData(plotData));
            pushMsg.setType(loseTypeEnum.getType());
            MessageHelper.sendPacket(userBaseInfo.getUserBaseInfo().getServerId(), userBaseInfo.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_PUSH_EGG_BE_TAKEN_MSG, pushMsg));
        }
    }

    /**
     * egg战斗
     * @param myPatronsMap
     * @param eggData
     * @return
     */
    public SonHaiBattleResp eggBattle(Map<Integer, SonHaiPatronsData> myPatronsMap, SonHaiEggData eggData, SonHaiRegionData regionData, SonHaiPlotData plotData) {
        //对方战力LIST
        List<SonHaiBeastData> targetBeastList = new ArrayList<>();
        List<SonHaiPatronsData> targetPatronsList = new ArrayList<>();
        //判断是兽，还是人
        int addRate;//我方战力加成
        int beastAddRate = 0;//异兽战力加成
        int targetPatronsAddRate = 0;     //驻守门客战力加成
        if (eggData.getUserId() > 0 && eggData.getPatronsDataMap().size() == 5) {
            targetPatronsList.addAll(eggData.getPatronsDataMap().values());
            addRate = this.getPowerAddRateForPvp();
            //驻守门客战力加成
            targetPatronsAddRate = eggData.getPatronsPowerAddRate(this.sonHaiConfig);
        } else {
            targetBeastList.addAll(eggData.getBeastGroupData().getBeastDataMap().values());
            addRate = this.getPowerAddRateForPve(regionData);
            //异兽战力加成
            beastAddRate = regionData.getPlotBeatsBattlePowerAddRate(plotData.getX(), plotData.getY(), this.sonHaiConfig);
        }
        //战斗
        List<SonHaiBattleOneResp> battleList = new ArrayList<>();
        int winNum = 0;
        int index = 0;
        long realDamage = 0;
        for (SonHaiPatronsData patronsData : myPatronsMap.values()){
            //门客战力
            long myPower = this.countPower(patronsData.getAbility(), addRate);//算上加成
            //战斗
            SonHaiBattleOneResp oneResp;
            if (eggData.getUserId() > 0 && eggData.getPatronsDataMap().size() == 5) {
                oneResp = this.eggBattleOnePvp(myPower, targetPatronsList.get(index), targetPatronsAddRate);
            } else {
                oneResp = this.eggBattleOnePve(myPower, targetBeastList.get(index), beastAddRate);
            }
            realDamage += oneResp.getRealDamage();
            battleList.add(oneResp);
            if (oneResp.isWinFlag()) {
                winNum++;
            }
            index++;
        }
        boolean winFlag = winNum >= 3;
        if (winFlag) {
            //真实伤害。如果是整体胜利，真实伤害则是剩余的全部血量。
            realDamage = eggData.getAllBlood();
        }
        //返回
        SonHaiBattleResp resp = new SonHaiBattleResp();
        resp.setWinFlag(winFlag);
        resp.setWinNum(winNum);
        resp.setBattleList(battleList);
        resp.setRealDamage(realDamage);
        return resp;
    }

    /**
     * 兽蛋战斗PVE-one by one，蛋战斗不掉血
     * @param myPower
     * @param beastData
     * @return
     */
    public SonHaiBattleOneResp eggBattleOnePve(long myPower, SonHaiBeastData beastData, int targetPowerAddRate) {
        //战力加成比例
        BigDecimal beatsPowerAddRateBig = BigDecimal.valueOf(targetPowerAddRate + 1000).divide(BigDecimal.valueOf(1000), 8,  RoundingMode.DOWN);
        //异兽总战力
        long beastConfigPower = beastData.getAllBlood();
        //加成后的总战力
        long targetPower = BigDecimal.valueOf(beastConfigPower).multiply(beatsPowerAddRateBig).longValue();
        //对方掉血
        long damage;
        if (myPower >= targetPower) {
            damage = targetPower;
        } else {
            damage = myPower;
        }
        //记录掉血明细
        beastData.addReBloodInfo(this.getUserId(), damage);
        //是否胜利
        boolean winFlag = myPower >= targetPower;
        //真实伤害 = 真实总血量 * 伤害比
        long realDamage = BigDecimal.valueOf(beastConfigPower).multiply(BigDecimal.valueOf(damage)).divide(BigDecimal.valueOf(targetPower), 8,  RoundingMode.DOWN).longValue();
        //返回
        SonHaiBattleOneResp resp = new SonHaiBattleOneResp();
        resp.setMyPower(myPower);
        resp.setTargetPower(targetPower);
        resp.setTargetTotalPower(targetPower);
        resp.setRealDamage(realDamage);
        resp.setDamage(myPower);
        resp.setWinFlag(winFlag);
        return resp;
    }

    /**
     * 兽蛋战斗PVP-one by one,蛋战斗不掉血
     * @param myPower
     * @param targetPatrons
     * @return
     */
    public SonHaiBattleOneResp eggBattleOnePvp(long myPower, SonHaiPatronsData targetPatrons, int targetPatronsAddRate) {
        //战力加成比例
        BigDecimal targetPatronsPowerAddRateBig = BigDecimal.valueOf(targetPatronsAddRate + 1000).divide(BigDecimal.valueOf(1000), 8,  RoundingMode.DOWN);
        //加成后的总战力
        long targetPower = BigDecimal.valueOf(targetPatrons.getAllBlood()).multiply(targetPatronsPowerAddRateBig).longValue();
        //战斗结果
        boolean winFlag = myPower >= targetPower;
        //对方掉血
        long damage;
        if (winFlag) {
            damage = targetPower;
        } else {
            damage = myPower;
        }
        //记录攻击
        targetPatrons.addReBloodInfo(this.getUserId(), damage);
        //返回
        SonHaiBattleOneResp resp = new SonHaiBattleOneResp();
        resp.setMyPower(myPower);
        resp.setTargetPower(targetPower);
        resp.setTargetTotalPower(targetPower);
        resp.setRealDamage(damage);
        resp.setDamage(damage);
        resp.setWinFlag(winFlag);
        return resp;
    }

    /**
     * 战斗后处理
     */
    private void afterBattle() {

    }

    /************************************************增减益处理*************************************************/


     /**********************************************战力增减*****************************************************/

    /**
     * 获取战力加成率-通用
     * @return
     */
    public int getPowerAddRateForAll() {
        int addPowerRate = 0;
        //门客天赋技能加成
        addPowerRate += this.getTalentAddition();
        //BUFF:当头棒喝,战力+{0}%
        SonHaiBuffData buffData2 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_2.getBuffId());
        if (buffData2 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData2.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData2.getLevel());
                addPowerRate += buffValueList.get(0);
            }
        }
        return addPowerRate;
    }

    /**
     * 获取PVP战力加成比例（只加PVP的）
     * @return
     */
    public int getPowerAddRateForOnlyPvp() {
        return 0;
    }

    /**
     * 获取PVE战力加成比例（只加PVE的）
     * @return
     */
    public int getPowerAddRateForOnlyPve(SonHaiRegionData regionData) {
        //地块收益
        int plotAddRate = regionData.getBattlePowerAddRateFromPlot(this.sonHaiConfig);
        //BUFF收益
        int buffAddRate = this.getPowerAddRateFromBuffPve();
        //返回
        return plotAddRate + buffAddRate;
    }

    /**
     * 获取PVE战力加成比例-BUFF收益-PVE
     * @return
     */
    private int getPowerAddRateFromBuffPve() {
        int addPowerRate = 0;
        //有舍有得,和异兽战斗时战力+{0}%，但获得的伏兽积分-{1}%
        SonHaiBuffData buffData3 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_3.getBuffId());
        if (buffData3 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData3.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData3.getLevel());
                addPowerRate += buffValueList.get(0);
            }
        }
        //和异兽战斗时战力-{0}%，但获得的伏兽积分+{1}%
        SonHaiBuffData buffData6 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_6.getBuffId());
        if (buffData6 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData6.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData6.getLevel());
                addPowerRate -= buffValueList.get(0);
            }
        }
        //和异兽战斗时战力+{0}%
        SonHaiBuffData buffData9 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_9.getBuffId());
        if (buffData9 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData9.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData9.getLevel());
                addPowerRate += buffValueList.get(0);
            }
        }
        //和异兽战斗战力-{0}%，获得的山海灵气+{1}%
        SonHaiBuffData buffData7 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_7.getBuffId());
        if (buffData7 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData7.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData7.getLevel());
                addPowerRate -= buffValueList.get(0);
            }
        }
        return addPowerRate;
    }

    /**
     * 获取战力加成rate-PVE
     * @param regionData
     * @return
     */
    public int getPowerAddRateForPve(SonHaiRegionData regionData) {
        int addRate = 0;
        //通用加成
        addRate += this.getPowerAddRateForAll();
        //只加PVE的加成
        addRate += this.getPowerAddRateForOnlyPve(regionData);
        //返回
        return addRate;
    }

    /**
     * 获取战力加成rate-PVP
     * @return
     */
    public int getPowerAddRateForPvp() {
        int addRate = 0;
        //通用加成
        addRate += this.getPowerAddRateForAll();
        //只加PVP的加成
        addRate += this.getPowerAddRateForOnlyPvp();
        //返回
        return addRate;
    }

    /**
     * 获取玩家PVE总战力-加成后的
     * @param regionData
     * @return
     */
    public long getPowerForPve(SonHaiRegionData regionData) {
        //计算战力加成
        int rate = this.getPowerAddRateForPve(regionData);
        return this.countUserPower(rate);
    }

    /**
     * 获取玩家PVE总战力-加成后的
     * @return
     */
    public long getPowerForPve() {
        return getPowerForPve(this.regionData);
    }

    /**
     * 获取玩家PVP总战力-加成后的
     * @return
     */
    public long getPowerForPvp() {
        //计算战力加成
        int rate = this.getPowerAddRateForPvp();
        return this.countUserPower(rate);
    }

    /**
     * 计算玩家战力
     * @param rate
     * @return
     */
    public long countUserPower(int rate) {
        long basePower = this.getPower();
        return this.countPower(basePower, rate);
    }

    /**
     * 计算战力
     * @param basePower
     * @param rate
     * @return
     */
    public long countPower(long basePower, int rate) {
        return BigDecimal.valueOf(basePower).multiply(BigDecimal.valueOf(1000 + rate)).divide(BigDecimal.valueOf(1000), 8,  RoundingMode.DOWN).longValue();
    }

    /*********************************************山海灵气益增减*******************************************************/

    /**
     * 获取山海灵气计算值
     * @param plotData
     * @param win
     * @return
     */
    public long getAuraScoreOpValue(SonHaiPlotData plotData, boolean win) {
        return 0;
    }

    /**
     * 获取山海灵气计算比例
     * @return
     */
    public int getAuraScoreOpRate(SonHaiPlotData plotData, boolean win) {
        int addRate = 0;
        //山海领取加成rate-无条件
        addRate += this.getAureScoreAddRateFromBuff();
        //山海领取加成rate-有条件
        addRate += this.getAureScoreAddRateFromBuffCondition(plotData, win);
        return addRate;
    }


    /**********************************************积分收益增减*****************************************************/

    /**
     * 获取积分计算值
     * @param win
     * @param eventProgress
     * @return
     */
    public long getScoreOpValue(boolean win, int eventProgress) {
        long scoreOpValue = 0;
        if (win) {
            //BUFF:镇伏地块时，额外获得该地块寻踪进度等量的伏兽积分
            scoreOpValue += this.winPlotExtraAddScoreFromBuff(eventProgress);
        }
        return scoreOpValue;
    }

    /**
     * 获取积分计算比例
     * @param regionData 区域
     * @param xyDataList 涉及的地块
     * @return
     */
    public int getScoreOpRate(SonHaiRegionData regionData, List<SonHaiXYData> xyDataList, boolean win, int plotLevel, int progress, boolean bossFlag) {
        //增减益-通用
        int addRate = this.getScoreAddRate(regionData);
        //增减益-地块
        int addRateFromPlot = this.getScoreAddRateFromPlot(regionData, xyDataList);
        //增减益-有条件
        SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(regionData.getRegionId());
        int progressRate = progress * 1000 / floorConfig.getNeedSchedule();//寻踪进度比例
        int addRateFromCondition = this.getConditionScoreAddRateFromBuff(win, plotLevel, progressRate, bossFlag);
        //总积分收益
        return addRate + addRateFromCondition + addRateFromPlot;
    }

    /**
     * 获取积分计算比例
     * @param regionData
     * @param x
     * @param y
     * @return
     */
    public int getScoreOpRate(SonHaiRegionData regionData, int x, int y, boolean win, int plotLevel, int progress) {
        List<SonHaiXYData> xyDataList = new ArrayList<>();
        xyDataList.add(new SonHaiXYData(x, y));
        return this.getScoreOpRate(regionData, xyDataList, win, plotLevel, progress, false);
    }

    /**
     * 获取积分加成比例-无条件的
     * @return
     */
    public int getScoreAddRate(SonHaiRegionData regionData) {
        //增减益-地块
        int plotAddRate = 0;
        if (regionData != null) {
            plotAddRate = regionData.getScoreAddRateFromPlot(this.sonHaiConfig);
        }
        //增减益-BUFF
        int buffAddRate = this.getScoreAddRateFromBuff();
        //增减益-持有兽蛋积分加成
        int eggAddRate = this.getEggScoreAddScore();
        return plotAddRate + buffAddRate + eggAddRate;
    }

    /**
     * 获取积分减少比例
     * @return
     */
    public int getScoreAddRateFromPlot(SonHaiRegionData regionData, List<SonHaiXYData> xyDataList) {
        //地块减益
        int plotReRate = regionData.getPlotScoreReduceRateForMul(xyDataList, this.sonHaiConfig);
        return -plotReRate;
    }

    /**
     * 获取积分加成比例-BUFF收益
     * @return
     */
    private int getScoreAddRateFromBuff() {
        int addScoreRate = 0;
        //多多益善,伏兽积分收益+{0}%
        SonHaiBuffData buffData1 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_1.getBuffId());
        if (buffData1 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData1.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData1.getLevel());
                addScoreRate += buffValueList.get(0);//读取配置，根据buffId和等级，获取积分增加比例
            }
        }
        //有舍有得,和异兽战斗时战力+{0}%，但获得的伏兽积分-{1}%
        SonHaiBuffData buffData3 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_3.getBuffId());
        if (buffData3 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData3.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData3.getLevel());
                addScoreRate -= buffValueList.get(1);
            }
        }
        //和异兽战斗时战力-{0}%，但获得的伏兽积分+{1}%
        SonHaiBuffData buffData6 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_6.getBuffId());
        if (buffData6 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData6.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData6.getLevel());
                addScoreRate += buffValueList.get(1);
            }
        }
        return addScoreRate;
    }

    /**
     * 获取积分收益（有条件的）-BUFF增益
     * @param win 是否镇伏
     * @param plotLevel 地块等级
     * @param progressRate 当前寻踪进度比例
     * @param bossFlag 是否是boss
     * @return
     */
    private int getConditionScoreAddRateFromBuff(boolean win, int plotLevel, int progressRate, boolean bossFlag) {
        int addScoreRate = 0;
        //意外之喜,获得伏兽积分时，有{0}%概率额外+{1}%伏兽积分
        SonHaiBuffData buffData4 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_4.getBuffId());
        if (buffData4 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData4.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData4.getLevel());
                int randomRate = buffValueList.get(0);//X%概率
                if (RandomHelper.randRate(randomRate)) {
                    addScoreRate += buffValueList.get(1);
                    //推送buff触发
                    this.syncBuffTriggerMsg(buffConfig.getId(), addScoreRate);
                }
            }
        }
        //镇伏等级低于X级的地块时，获得的伏兽积分+X%
        if (win) {
            SonHaiBuffData buffData10 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_10.getBuffId());
            if (buffData10 != null) {
                SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData10.getBuffId());
                if (buffConfig != null) {
                    List<Integer> buffValueList = buffConfig.getBuffValueList(buffData10.getLevel());
                    if (plotLevel < buffValueList.get(0)) {
                        addScoreRate += buffValueList.get(1);
                    }
                }
            }
        }
        //所在地区寻踪进度大于X时，获得的伏兽积分+{1}%
        SonHaiBuffData buffData13 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_13.getBuffId());
        if (buffData13 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData13.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData13.getLevel());
                if (progressRate > buffValueList.get(0)) {
                    addScoreRate += buffValueList.get(1);
                }
            }
        }
        //兽王地块奖励提供的伏兽积分奖励+X%
        if (bossFlag) {
            SonHaiBuffData buffData19 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_19.getBuffId());
            if (buffData19 != null) {
                SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData19.getBuffId());
                if (buffConfig != null) {
                    List<Integer> buffValueList = buffConfig.getBuffValueList(buffData19.getLevel());
                    addScoreRate += buffValueList.get(0);
                }
            }
        }
        return addScoreRate;
    }

    /**
     * 获取持有兽蛋积分加成
     * @return
     */
    public int getEggScoreAddScore() {
        int addRate = 0;
        for (SonHaiEggData eggData : this.userEggDataMap.values()) {
            //读配置
            SonHaiEggConfig eggConfig = this.sonHaiConfig.getEggConfig(eggData.getEggConfigId());
            if (eggConfig == null) {
                continue;
            }
            addRate += eggConfig.getParamList().get(1);
        }
        return addRate;
    }

    /**********************************************寻踪进度收益增减*****************************************************/

    /**
     * 计算额外加成的寻踪进度
     * @param baseProgress
     * @param rate
     * @param value
     * @return
     */
    public int countExtraProgress(int baseProgress, int rate, int value) {
        BigDecimal rateBig = BigDecimal.valueOf(rate).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
        int extraProgress = BigDecimal.valueOf(baseProgress).multiply(rateBig).setScale(0, RoundingMode.UP).intValue();
        return extraProgress + value;
    }

    /**
     * 获取获取能额外计算（增加/减少）的探索进度-加成率
     * @param regionData
     * @return
     */
    public int getProgressOpRate(SonHaiRegionData regionData) {
        int addRate = 0;
        //无条件的
        addRate += this.getProgressOpRateNotCondition(regionData);
        return addRate;
    }

    /**
     * 无条件的寻踪进度加成rate
     * @return
     */
    public int getProgressOpRateNotCondition(SonHaiRegionData regionData) {
        int addRate = 0;
        //指点迷津,镇伏地块时，额外+{0}寻踪进度
        SonHaiBuffData buffData5 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_5.getBuffId());
        if (buffData5 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData5.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData5.getLevel());
                addRate += buffValueList.get(0);
            }
        }
        //所在地区寻踪进度小于{0%}时，镇伏地块额外获得{1}%寻踪进度
        int progressRate = 0;
        if (regionData != null) {
            SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(regionData.getRegionId());
            progressRate = regionData.getProgress() * 1000 / floorConfig.getNeedSchedule();//寻踪进度比
        }
        SonHaiBuffData buffData12 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_12.getBuffId());
        if (buffData12 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData12.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData12.getLevel());
                if (progressRate < buffValueList.get(0)) {
                    addRate += buffValueList.get(1);
                }
            }
        }
        return addRate;
    }

    /**
     * 获取获取能额外计算（增加/减少）的探索进度-加成值
     * @param x
     * @param y
     * @return
     */
    public int getProgressOpValue(int x, int y) {
        //增益处理
        int extraAddProgress = this.getProgressAddValue();
        //减益处理
        int reduceProgress = regionData.getPlotProgressReduceValue(x, y, this.sonHaiConfig);
        //计算最终增加的寻踪进度
        return extraAddProgress - reduceProgress;
    }

    /**
     * 获取能额外增加的探索进度
     * @return
     */
    public int getProgressAddValue() {
        //地块收益
        int plotAddValue = this.getProgressAddValueFromPlot();
        //BUFF收益
        int buffAddVale = this.getProgressAddValueFromBuff();
        return plotAddValue + buffAddVale;
    }

    /**
     * 获取能额外增加的探索进度-地块收益
     * @return
     */
    private int getProgressAddValueFromPlot() {
        return 0;
    }

    /**
     * 获取能额外增加的探索进度-BUFF收益
     * @return
     */
    private int getProgressAddValueFromBuff() {
        return 0;
    }

    /**
     * 获取能额外增加的山海灵气-BUFF收益
     * @return
     */
    private int getAureScoreAddRateFromBuff() {
        int addAuraScoreRate = 0;
        //战力-{0}%，获得的山海灵气+{1}%
        SonHaiBuffData buffData7 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_7.getBuffId());
        if (buffData7 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData7.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData7.getLevel());
                addAuraScoreRate += buffValueList.get(1);
            }
        }
        return addAuraScoreRate;
    }

    /**
     * 计算加成后的山海灵气
     * @param aureScore 基础
     * @param rate 加成率
     * @param value 加成值
     * @return
     */
    public long countAureScore(long aureScore, int rate, long value) {
        BigDecimal rateBig = BigDecimal.valueOf(rate).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
        long extraAddSuraScore = BigDecimal.valueOf(aureScore).multiply(rateBig).setScale(0, RoundingMode.UP).intValue();
        extraAddSuraScore += value;
        return aureScore + extraAddSuraScore;
    }

    /**
     * 恢复体力-buff
     * @return
     */
    private int recoverHpFromBuff() {
        int recoverHp = 0;
        //镇伏兽群地块后，X%概率恢复1点体力
        SonHaiBuffData buffData8 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_8.getBuffId());
        if (buffData8 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData8.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData8.getLevel());
                int randomRate = buffValueList.get(0);
                if (RandomHelper.randRate(randomRate)) {
                    //恢复体力
                    recoverHp = 1;
                    this.addEnergy(recoverHp);
                    //体力恢复日志
                    LogCrossSonHaiEnergy log = new LogCrossSonHaiEnergy(
                            this.getActivityId(),
                            this.getGroupId(),
                            this.getUserId(),
                            this.getTeamId(),
                            SonHaiLogEnergyTypeEnum.BUFF_ADD.getType(),
                            recoverHp,
                            this.getEnergy()
                    );
                    CrossAutoLogMgr.add(log);
                    //推送buff触发
                    this.syncBuffTriggerMsg(buffConfig.getId(), recoverHp);
                }
            }
        }
        return recoverHp;
    }

    /**
     * 发现异兽栖地块时，获得该地块等量的伏兽积分奖励
     * @param plotScore
     * @return
     */
    public long findEggAddScoreFromBuff(long plotScore) {
        long addScore = 0;
        //发现异兽栖地块时，获得该地块{0}%的伏兽积分奖励
        SonHaiBuffData buffData14 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_14.getBuffId());
        if (buffData14 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData14.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData14.getLevel());
                BigDecimal rate = BigDecimal.valueOf(buffValueList.get(0)).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
                addScore += BigDecimal.valueOf(plotScore).multiply(rate).longValue();
            }
        }
        return addScore;
    }

    /**
     * 领取兽王奖励时，额外获得{0}%山海灵气
     * @return
     */
    public int getAureScoreAddRateFromBuffCondition(SonHaiPlotData plotData, boolean win) {
        int addRate = 0;
        //镇伏地块时，{0}%概率额外获得{1}%的山海灵气
        if (win) {
            SonHaiBuffData buffData11 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_11.getBuffId());
            if (buffData11 != null) {
                SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData11.getBuffId());
                if (buffConfig != null) {
                    List<Integer> buffValueList = buffConfig.getBuffValueList(buffData11.getLevel());
                    int randomRate = buffValueList.get(0);
                    if (RandomHelper.randRate(randomRate)) {
                        addRate += buffValueList.get(1);
                        //推送buff触发
                        this.syncBuffTriggerMsg(buffConfig.getId(), buffValueList.get(1));
                    }
                }
            }
        }
        //领取兽王奖励时，额外获得{0}%山海灵气
        if (win && plotData.getType() == SonHaiPlotTypeEnum.PLOT_TYPE_1.getType()) {
            SonHaiBuffData buffData16 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_16.getBuffId());
            if (buffData16 != null) {
                SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData16.getBuffId());
                if (buffConfig != null) {
                    List<Integer> buffValueList = buffConfig.getBuffValueList(buffData16.getLevel());
                    addRate += buffValueList.get(0);
                }
            }
        }
        return addRate;
    }

    /**
     * 触发当康巢地块时，额外多探明x个地块
     * @return
     */
    public int extraExplorePlot() {
        int num = 0;
        //触发当康巢地块时，额外多探明x个地块
        SonHaiBuffData buffData17 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_17.getBuffId());
        if (buffData17 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData17.getBuffId());
            if (buffConfig != null) {
                num += 1;
                //推送buff触发
                this.syncBuffTriggerMsg(buffConfig.getId(), 1);
            }
        }
        return num;
    }

    /**
     * 镇伏地块时，额外获得该地块寻踪进度{0}%的伏兽积分
     * @param progress
     * @return
     */
    public long winPlotExtraAddScoreFromBuff(int progress) {
        long addScore = 0;
        //镇伏地块时，额外获得该地块寻踪进度{0}%的伏兽积分
        SonHaiBuffData buffData18 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_18.getBuffId());
        if (buffData18 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData18.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData18.getLevel());
                BigDecimal rate = BigDecimal.valueOf(buffValueList.get(0)).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
                addScore += BigDecimal.valueOf(progress).multiply(rate).longValue();
            }
        }
        return addScore;
    }

    /**
     * 触发队友协战时，最高战力队友的出战概率提升
     * @return
     */
    public int randomMaxPowerHelpAddRateFromBuff() {
        int rate = 0;
        //触发队友协战时，最高战力队友的出战概率提升
        SonHaiBuffData buffData15 = this.getBuff(SonHaiBuffTypeEnum.BUFF_TYPE_15.getBuffId());
        if (buffData15 != null) {
            SonHaiBuffConfig buffConfig = this.sonHaiConfig.getBuffConfig(buffData15.getBuffId());
            if (buffConfig != null) {
                List<Integer> buffValueList = buffConfig.getBuffValueList(buffData15.getLevel());
                rate += buffValueList.get(0);
                //推送buff触发
                this.syncBuffTriggerMsg(buffConfig.getId(), buffValueList.get(0));
            }
        }
        return rate;
    }


    /************************************************增减益处理*************************************************/

    /**
     * 推送buff触发
     * @param buffId
     */
    private void syncBuffTriggerMsg(int buffId, int value) {
        SonHaiProto.SonHaiTriggerBuffSyncMsg.Builder builder = SonHaiProto.SonHaiTriggerBuffSyncMsg.newBuilder();
        builder.setBuffId(buffId);
        builder.setValue(value);
        MessageHelper.sendPacket(this.getServerId(), this.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_SYNC_TRIGGER_BUFF, builder));
    }

    /**
     * 检查CD中
     * @param userId
     * @return true:cd中，false:没cd中
     */
    public boolean checkHelpCd(long userId) {
        SonHaiReBloodInfo reBloodInfo = this.getReBloodInfoMap().get(userId);
        if (reBloodInfo != null ) {
            long helpCdEndTime = this.getHelpCdEndTime(userId);
            if (helpCdEndTime >= System.currentTimeMillis()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取cd结束时间
     * @param userId
     * @return
     */
    public long getHelpCdEndTime(long userId) {
        long cdTime = this.sonHaiConfig.getHelpCd() * DateHelper.SECOND_MILLIONS;
        SonHaiReBloodInfo reBloodInfo = this.getReBloodInfoMap().get(userId);
        if (reBloodInfo != null) {
            return reBloodInfo.getTime() + cdTime;
        }
        return 0;
    }

    /**
     * 获取商会ID
     * @return
     */
    public String getUnionId() {
        UnionActivityGroupUnion unionData = Cross2UnionActivityGroupMgr.getUnionData(this.getActivityId(), this.getUserId());
        if (unionData != null) {
            return unionData.getUnionUid();
        }
        return null;
    }

    /**
     * 获取商会成员MAP
     * @return
     */
    public Map<Long, UnionActivityGroupUser> getUnionUserMap() {
        UnionActivityGroupUnion unionData = Cross2UnionActivityGroupMgr.getUnionData(this.getActivityId(), this.getUserId());
        if (unionData != null) {
            return unionData.getUserMap();
        }
        return null;
    }

    /**
     * 添加战斗日志
     * @param battleLog
     */
    public void addBattleLog(SonHaiBattleLog battleLog) {
        this.battleLogList.add(battleLog);
    }

    /**
     * 获取战斗日志
     * @return
     */
    public FixSizeLinkedList<SonHaiBattleLog> getBattleLogList() {
        return this.battleLogList;
    }

    /**
     * 获取BOSS红点(是否有BOSS打 || 是否有boss奖励可领取)
     * @return
     */
    public boolean getBossRedDot() {
        //获取区域MAP
        CrossSonHaiTeam team = this.getTeam();
        if (team != null) {
            Map<Integer, SonHaiRegionData> regionMap = team.getRegionMap();
            if (regionMap != null) {
                for (SonHaiRegionData regionData : regionMap.values()) {
                    //区域寻踪进度达到就有【兽王踪迹】红点
                    SonHaiFloorConfig floorConfig = this.sonHaiConfig.getFloorConfig(regionData.getRegionId());
                    if (regionData.getProgress() >= floorConfig.getNeedSchedule()) {
                        //boss是否还在
                        SonHaiBeastBossData boss = regionData.getBeastBoss();
                        if (boss.getWinFlag() == SonHaiWinFlagEnum.WIN_NOT.getType()) {
                            //未镇伏
                            return true;
                        } else {
                            //已镇伏 && 奖励未领取
                            if (!boss.checkReceiveReward(this.getUserId())) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * 探险互助红点
     * @return
     */
    public boolean getUserHelpRedDot() {
        //获取区域MAP
        CrossSonHaiTeam team = this.getTeam();
        if (team != null) {
            Map<Integer, SonHaiRegionData> regionMap = team.getRegionMap();
            if (regionMap != null) {
                for (SonHaiRegionData regionData : regionMap.values()) {
                    boolean flag = regionData.getUserHelpRedDot(this.getUserId());
                    if (flag) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 可领取兽蛋奖励红点
     * @return
     */
    public boolean getEggRewardRedDot() {
        int num = this.getNotReceiveEggRewardNum();
        return num > 0;
    }

    /**
     * 同步红点（红点最新处理方式）
     * @param eggRewardRedDot
     * @param userHelpRedDot
     * @param bossRedDot
     */
    public void syncRedDotMsg(SonHaiRedDotTypeEnum eggRewardRedDot, SonHaiRedDotTypeEnum userHelpRedDot, SonHaiRedDotTypeEnum bossRedDot) {
        SonHaiProto.SonHaiSyncRedDotMsg.Builder builder = SonHaiProto.SonHaiSyncRedDotMsg.newBuilder();
        builder.setEggRewardRedDot(eggRewardRedDot.getType());
        builder.setUserHelpRedDot(userHelpRedDot.getType());
        builder.setBossRedDot(bossRedDot.getType());
        MessageHelper.sendPacket(this.getServerId(), this.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_SON_HAI_SYNC_RED_DOT, builder));
    }

    /**
     * 同步所有红点（登录下发）
     */
    public void syncAllRedDotMsg() {
        //兽蛋奖励红点
        SonHaiRedDotTypeEnum eggRewardRedDot = this.getEggRewardRedDot() ? SonHaiRedDotTypeEnum.TYPE_HAVE : SonHaiRedDotTypeEnum.TYPE_NOT_HAVE;
        //协助奖励红点
        SonHaiRedDotTypeEnum userHelpRedDot = this.getUserHelpRedDot() ? SonHaiRedDotTypeEnum.TYPE_HAVE : SonHaiRedDotTypeEnum.TYPE_NOT_HAVE;
        //boss红点
        SonHaiRedDotTypeEnum bossRedDot = this.getBossRedDot() ? SonHaiRedDotTypeEnum.TYPE_HAVE : SonHaiRedDotTypeEnum.TYPE_NOT_HAVE;
        //同步红点
        this.syncRedDotMsg(eggRewardRedDot, userHelpRedDot, bossRedDot);
    }
}
